package com.tengju.settlement.infrastructure.repository;

import com.google.common.collect.Lists;
import com.tengju.settlement.domain.model.account.UserIdCode;
import com.tengju.settlement.domain.model.depository.BindStatus;
import com.tengju.settlement.domain.model.depository.DepositoryAccountId;
import com.tengju.settlement.domain.model.depository.DepositoryBankCard;
import com.tengju.settlement.domain.model.depository.DepositoryBankCardRepository;
import com.tengju.settlement.domain.shared.IdObject;
import com.tengju.settlement.infrastructure.persistence.mybatis.dataobject.DepositoryBankCardDO;
import com.tengju.settlement.infrastructure.persistence.mybatis.mapper.tengju.custom.DepositoryBankCardMapper;
import com.tengju.settlement.infrastructure.persistence.redis.DepositoryCacheRepository;
import com.tengju.settlement.infrastructure.persistence.redis.dataobject.RedisKeyObject;
import com.tengju.settlement.infrastructure.persistence.redis.dataobject.RedisKeyPrefix;
import com.tengju.settlement.infrastructure.repository.convert.DepositoryBankCardConvert;
import com.tengju.settlement.infrastructure.shared.InfraException;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import org.springframework.util.CollectionUtils;

import java.time.LocalDate;
import java.util.List;
import java.util.stream.Collectors;

@Repository
@RequiredArgsConstructor(onConstructor_ ={@Autowired})
@Slf4j
public class DepositoryBankCardRepositoryImpl implements DepositoryBankCardRepository {

    private final DepositoryBankCardMapper depositoryBankCardMapper;
    private final DepositoryCacheRepository depositoryRepository;



    @Override
    public List<DepositoryBankCard> getByDepositoryAccountIdStatus(UserIdCode idCode, DepositoryAccountId accountId, List<BindStatus> bindStatus) {
        List<Integer> bindStatusVal = bindStatus.stream()
                .map(BindStatus::getVal).collect(Collectors.toList());
        List<DepositoryBankCardDO> depositoryBankCardDOList = depositoryBankCardMapper
                .getByDepositoryAccountIdStatus(idCode.getValue(), accountId.getValue(), bindStatusVal);

        if (CollectionUtils.isEmpty(depositoryBankCardDOList)) {
            return Lists.newArrayList();
        }

        return depositoryBankCardDOList.stream()
                .map(DepositoryBankCardConvert::convertToModel)
                .collect(Collectors.toList());
    }

    @Override
    public List<DepositoryBankCard> getByDepositoryAccountIdsStatus(List<DepositoryAccountId> accountIds, List<BindStatus> bindStatus) {
        List<Long> depositoryAccountIdVals = accountIds.stream()
                .map(IdObject::getValue).collect(Collectors.toList());
        List<Integer> bindStatusVal = bindStatus.stream()
                .map(BindStatus::getVal).collect(Collectors.toList());

        List<DepositoryBankCardDO> depositoryBankCardDOList =
                depositoryBankCardMapper.getByDepositoryAccountIdsStatus(depositoryAccountIdVals, bindStatusVal);
        return depositoryBankCardDOList.stream()
                .map(DepositoryBankCardConvert::convertToModel).collect(Collectors.toList());
    }

//    @Override
//    public List<DepositoryBankCard> getByIdCodesStatus(List<UserIdCode> idCodes, List<BindStatus> bindStatus) {
//        List<Long> idCodeVals = idCodes.stream().map(IdObject::getValue).collect(Collectors.toList());
//        List<Integer> bindStatusVals = bindStatus.stream().map(BindStatus::getVal).collect(Collectors.toList());
//        List<DepositoryBankCardDO> bankCardDOList =
//                depositoryBankCardMapper.getByIdCodesStatus(idCodeVals, bindStatusVals);
//        return bankCardDOList.stream().map(DepositoryBankCardConvert::convertToModel).collect(Collectors.toList());
//    }

    @Override
    public DepositoryBankCard getByDepositoryAccountIdCardNo(UserIdCode idCode, DepositoryAccountId accountId, String cardNo) {
        DepositoryBankCardDO depositoryAccountIdBankNoDO =
                depositoryBankCardMapper.getByDepositoryAccountIdBankNo(idCode.getValue(), accountId.getValue(), cardNo);
        return DepositoryBankCardConvert.convertToModel(depositoryAccountIdBankNoDO);
    }

    @Override
    public DepositoryBankCard getByCardNo(UserIdCode idCode, String cardNo) {
        DepositoryBankCardDO depositoryAccountIdBankNoDO =
                depositoryBankCardMapper.getByBankNo(idCode.getValue(), cardNo);
        return DepositoryBankCardConvert.convertToModel(depositoryAccountIdBankNoDO);
    }

    @Override
    public void updateBindStatus(DepositoryBankCard depositoryBankCard) {
        DepositoryBankCardDO bankCardDO = DepositoryBankCardConvert.convertToDO(depositoryBankCard);
        depositoryBankCardMapper.updateBindStatus(bankCardDO);
    }

    @Override
    public void updateByBankCardId(DepositoryBankCard depositoryBankCard) {
        DepositoryBankCardDO bankCardDO = DepositoryBankCardConvert.convertToDO(depositoryBankCard);
        depositoryBankCardMapper.updateByBankCardId(bankCardDO);
    }

    @Override
    public void save(DepositoryBankCard depositoryBankCard) {
        DepositoryBankCardDO bankCardDO = DepositoryBankCardConvert.convertToDO(depositoryBankCard);
        depositoryBankCardMapper.insertOrUpdate(bankCardDO);
    }

    @Override
    public void bindCardCntInit(UserIdCode idCode, int bindCardCnt, int expireHours) {
        String key = String.valueOf(idCode.getValue()) + LocalDate.now();
        boolean res = depositoryRepository.setBindCardCnt(new RedisKeyObject(RedisKeyPrefix.BIND_CARD_VALID_CNT, key), bindCardCnt, expireHours);
        if (!res){
            log.error("redis: 设置绑卡的有效次数key失败, idCode: {}", idCode);
            throw new InfraException("redis: 设置绑卡初始化key失败");
        }
    }

    @Override
    public void bindCntIncrement(UserIdCode idCode) {
        String key = String.valueOf(idCode.getValue()) + LocalDate.now();
        boolean res = depositoryRepository.bindCntIncr(new RedisKeyObject(RedisKeyPrefix.BIND_CARD_VALID_CNT, key));
        if (!res){
            log.error("redis: 绑卡次数自增失败, idCode: {}", idCode);
            throw new InfraException("redis: 绑卡次数 +1 失败");
        }
    }

    @Override
    public Integer bindCardCnt(UserIdCode idCode) {
        String key = String.valueOf(idCode.getValue()) + LocalDate.now();
        return depositoryRepository.getBindCardValue(new RedisKeyObject(RedisKeyPrefix.BIND_CARD_VALID_CNT, key));
    }

    @Override
    public void delCardCnt(UserIdCode idCode) {
        String key = String.valueOf(idCode.getValue()) + LocalDate.now();
        depositoryRepository.delBindCardKey(new RedisKeyObject(RedisKeyPrefix.BIND_CARD_VALID_CNT, key));
    }

    @Override
    public boolean existCntKey(UserIdCode idCode) {
        String key = String.valueOf(idCode.getValue()) + LocalDate.now();
        return depositoryRepository.existBindCardKey(new RedisKeyObject(RedisKeyPrefix.BIND_CARD_VALID_CNT, key));
    }

    @Override
    public Long bindCntTtl(UserIdCode idCode) {
        String key = String.valueOf(idCode.getValue()) + LocalDate.now();
        return depositoryRepository.getBindCardExpireTime(new RedisKeyObject(RedisKeyPrefix.BIND_CARD_VALID_CNT, key));
    }
}
